﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using SharePoint.Sunbox.Sandbox.Core;
using SharePoint.Sunbox.Sandbox.Resources;

namespace SharePoint.Sunbox.Sandbox.DataViewWebPart
{
    [ToolboxItem(false)]
    public class DataViewWebPart : WebPart, IWebEditable
    {
        private const string FolderPath = "Style Library/Sunbox/SunboxDataView/XSL";

        [Personalizable(PersonalizationScope.Shared),
         WebBrowsable(false)]
        public string DataSourcesData { get; set; }

        [Personalizable(PersonalizationScope.Shared), WebBrowsable(false)]
        public string XslSourceTitle { get; set; }

        [Personalizable(PersonalizationScope.Shared), WebBrowsable(false)]
        public string XslSourceData { get; set; }

        [Personalizable(PersonalizationScope.Shared), WebBrowsable(false)]
        public string XslSourceLastModified { get; set; }

        [Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         LocalizedWebDisplayNameAttribute("DataViewWebPartJsObjectPropertyTitle"),
         LocalizedWebDescriptionAttribute("DataViewWebPartJsObjectPropertyDescription"),
         DefaultValue("")]
        public string JsObjectName { get; set; }

        [Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         LocalizedWebDisplayNameAttribute("DataViewWebPartInitFunctionPropertyTitle"),
         DefaultValue(""),
         LocalizedWebDescriptionAttribute("DataViewWebPartInitFunctionPropertyDescription")]
        public string InitFunctionName { get; set; }


        [Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         LocalizedWebDisplayNameAttribute("DataViewWebPartShowLoaderImagePropertyTitle"),
         DefaultValue(false)]
        public bool ShowLoader { get; set; }

        [Personalizable(PersonalizationScope.User), WebBrowsable(true),
         LocalizedWebDisplayNameAttribute("DataViewWebPartDebugModePropertyTitle"),
         DefaultValue(false)]
        public bool DebugMode { get; set; }


        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            LoadXsl();
            //Set last modified date of the datasources:
            ProcessDataSources();
        }

        #region IWebEditable Members

        EditorPartCollection IWebEditable.CreateEditorParts()
        {
            // control the editorparts
            var editors = new List<EditorPart>();
            var dataSourcesEditorPart = new DataSourcesEditorPart
            {
                ID = ID + "_datasourceeditorPart",
                Title = Properties.DataSourcesEditorPartTitle
            };
            editors.Add(dataSourcesEditorPart);
            var xslSourceEditorPart = new XslDataEditorPart
            {
                ID = ID + "_xslsourceeditorPart",
                Title = Properties.XslEditorPartTitle
            };

            editors.Add(xslSourceEditorPart);
            return new EditorPartCollection(editors);
        }

        object IWebEditable.WebBrowsableObject
        {
            get { return this; }
        }

        #endregion

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);

            string siteUrl = SPContext.Current.Site.RootWeb.Url;
            string containerId = string.Format("sunboxdataview-outer-{0}", Guid.NewGuid().ToString());

            //XSL:
            string xsl = Helpers.SerializeObject(new XslSourceTemplate { Title = XslSourceTitle, Xsl = SPEncode.HtmlEncode(XslSourceData) });



            writer.Write(string.Format("<div id=\"{0}\"></div>", containerId));
            writer.Write("<script>");
            //SharePoint.Orm
            writer.Write(
                string.Format(
                    "if (!window.SharePointOrmIncluded) document.write(\"<script\" + \" src='{0}/Style Library/Sunbox/Scripts/sharepoint.orm.js'><\" + \"/script>\"); ",
                    siteUrl));
            //DataViewWebPart script

            string dataViewScriptFile = DebugMode ? "sunbox.dataview.js" : "sunbox.dataview.pack.js";
#if DEBUG
            dataViewScriptFile = "sunbox.dataview.js";
#endif


            writer.Write(
            string.Format(
                "if (!window.sunboxDataViewScriptIncluded) document.write(\"<script\" + \" src='{0}/Style Library/Sunbox/SunboxDataView/Scripts/{1}'><\" + \"/script>\"); ",
                siteUrl, dataViewScriptFile));
            //Language
            writer.Write(
                string.Format(
                    "document.write(\"<script\" + \" src='{0}/Style Library/Sunbox/SunboxDataView/Scripts/lang/{1}.js'><\" + \"/script>\"); ",
                    siteUrl, Properties.Language));

            writer.Write("</script>");
            //init dataview:
            writer.Write("<script>");
            writer.Write(
                string.Format(
                    "var __sunboxoptions = {{debug: {0}, datasources:{1}, initFunction:{2}, showloader: {3}, loaderimage: \"{4}\", xsltemplate: {5}, lang:\"{6}\" }};",
                    DebugMode.ToString(CultureInfo.InvariantCulture).ToLower(), //debug mode
                    string.IsNullOrEmpty(DataSourcesData) ? "[]" : DataSourcesData, //datasources
                    string.IsNullOrEmpty(InitFunctionName) ? "null" : InitFunctionName, //init function
                    ShowLoader.ToString(CultureInfo.InvariantCulture).ToLower(), // show loader
                    "/_layouts/images/gears_anv4.gif", //loader image
                    xsl, // xsl template
                    Properties.Language
                    ));
            writer.Write(string.Format("var {0} = new SunboxDataView(document.getElementById(\"{1}\"), __sunboxoptions);",
                                       string.IsNullOrEmpty(JsObjectName)
                                           ? "sunboxDataView"
                                           : JsObjectName,
                                       containerId
                             ));

            writer.Write("</script>");
        }

        private void ProcessDataSources()
        {
            //put modified date to each data source:
            if (!string.IsNullOrEmpty(DataSourcesData))
            {
                var sources = Helpers.DeserializeObject<List<SunboxDataViewDataSource>>(DataSourcesData);
                bool sourcesChanged = false;
                bool saveSources = false;
                foreach (SunboxDataViewDataSource t in sources)
                {
                    var listId = new Guid(t.ListId);
                    try
                    {
                        string currentModifiedDate;
                        if (string.IsNullOrEmpty(t.WebUrl))
                            currentModifiedDate = GetListModifiedDate(SPContext.Current.Web, listId).ToString(CultureInfo.InvariantCulture);
                        else
                        {
                            //determine web url
                            string webUrl = t.WebUrl;
                            if (!t.WebUrl.StartsWith("/"))
                                webUrl = "/" + webUrl;
                            using (var site = new SPSite(SPContext.Current.Web.Url + webUrl))
                            {
                                using (SPWeb web = site.OpenWeb())
                                {
                                    currentModifiedDate = GetListModifiedDate(web, listId).ToString(CultureInfo.InvariantCulture);
                                }
                            }
                        }

                        if (string.IsNullOrEmpty(t.Modified) || currentModifiedDate != t.Modified)
                        {
                            t.Modified = currentModifiedDate;
                            sourcesChanged = true;
                        }
                        if (!t.CacheOnClient.HasValue)
                        {
                            t.CacheOnClient = true; //default value for older data source (previous versions)
                            sourcesChanged = true;
                            saveSources = true;
                        }
                    }
                    catch (Exception)
                    {
                        t.CacheOnClient = false; // clent caching not allowed if we cant to retreive last modified date of the source
                        sourcesChanged = true;
                        saveSources = true;
                    }
                }

                if (sourcesChanged)
                {
                    DataSourcesData = Helpers.SerializeObject(sources); //save modified data sources if it changes
                    if (saveSources)
                        SetPersonalizationDirty();
                }
            }
        }

        private DateTime GetListModifiedDate(SPWeb web, Guid listId)
        {
            return web.Lists[listId].LastItemModifiedDate;
        }

        private void LoadXsl()
        {
            if (!string.IsNullOrEmpty(XslSourceTitle))
            {
                try
                {
                    SPFile xslFile = SPContext.Current.Web.Site.RootWeb.GetFile(FolderPath + "/" + XslSourceTitle);
                    if (xslFile != null)
                    {
                        //check cache:
                        string lastModifiedStamp = xslFile.TimeLastModified.ToString(CultureInfo.InvariantCulture);
                        if (XslSourceLastModified != lastModifiedStamp)
                        {
                            XslSourceLastModified = lastModifiedStamp;
                            XslSourceData = GetFileData(xslFile).Replace(Environment.NewLine, "").Replace("\n", "");
                            SetPersonalizationDirty();
                        }
                    }
                }
                catch (Exception)
                {
                    XslSourceData = string.Empty;
                }
            }
        }

        private string GetFileData(SPFile spFile)
        {
            if (spFile == null)
                return string.Empty;
            try
            {
                var encoding = new UTF8Encoding(false);
                byte[] bytes = spFile.OpenBinary();
                return encoding.GetString(bytes);
            }
            catch
            {
                return string.Empty;
            }
        }
    }
}